package io.github.wanggit.antcms.server.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ImageUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.wanggit.antcms.server.domain.AntArticle;
import io.github.wanggit.antcms.server.domain.AntArticleMedia;
import io.github.wanggit.antcms.server.domain.AntMedia;
import io.github.wanggit.antcms.server.mapper.AntMediaMapper;
import io.github.wanggit.antcms.server.service.ArticleMediaService;
import io.github.wanggit.antcms.server.service.MediaService;
import io.github.wanggit.antcms.server.service.impl.utils.MediaUtil;
import io.github.wanggit.antcms.server.web.MediaController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class MediaServiceImpl extends ServiceImpl<AntMediaMapper, AntMedia>
        implements MediaService {

    private static final Logger logger = LoggerFactory.getLogger(MediaController.class);

    @Autowired private MediaUtil mediaUtil;

    @Autowired private ArticleMediaService articleMediaService;

    @Value("${application.media.dir}")
    private String mediaDir;

    @Value("${application.preview.dir}")
    private String previewHomeDir;

    @Override
    public void deleteMedias(List<Long> ids) {
        List<AntMedia> antMedias = getBaseMapper().selectBatchIds(ids);
        antMedias.forEach(
                it -> {
                    FileUtil.del(previewHomeDir + mediaDir + "/" + it.getFileName());
                    removeById(it.getId());
                });
    }

    @Override
    public AntMedia saveImageWhenCreateArticle(String imageBase64) {
        String contentType =
                imageBase64.substring(0, imageBase64.indexOf(";")).replace("data:", "");
        byte[] imageBytes =
                Base64.decode(
                        imageBase64.substring(imageBase64.indexOf(',') + 1),
                        CharsetUtil.CHARSET_UTF_8);
        BufferedImage bufferedImage = ImageUtil.toImage(imageBytes);
        String title = UUID.randomUUID().toString();
        String fileName = title + "." + mediaUtil.contentTypeToFileSubfix(contentType);
        ImageUtil.write(bufferedImage, new File(previewHomeDir + mediaDir + "/" + fileName));
        AntMedia media = new AntMedia();
        media.setWasImage(true);
        media.setUrl(mediaDir + "/" + fileName);
        media.setFileHeight(bufferedImage.getHeight());
        media.setFileWidth(bufferedImage.getWidth());
        media.setFileName(fileName);
        media.setUploadTime(new Date());
        media.setOriginFileName(fileName);
        media.setFileType(contentType);
        media.setFileSize((long) imageBytes.length);
        media.setTitle(title);
        save(media);
        return media;
    }

    @Override
    public AntMedia saveMedia(MultipartFile multipartFile) {
        AntMedia media = new AntMedia();
        media.setFileSize(multipartFile.getSize());
        media.setFileType(multipartFile.getContentType());
        String originName = multipartFile.getOriginalFilename();
        media.setOriginFileName(originName);
        media.setUploadTime(new Date());
        media.setFileName(
                UUID.randomUUID().toString() + originName.substring(originName.lastIndexOf(".")));
        media.setTitle(originName.substring(0, originName.lastIndexOf(".")));
        media.setWasImage(media.getFileType().startsWith("image/"));
        try {
            if (null != media.getWasImage() && media.getWasImage()) {
                BufferedImage bufferedImage = ImageUtil.read(multipartFile.getInputStream());
                media.setFileWidth(bufferedImage.getWidth(null));
                media.setFileHeight(bufferedImage.getHeight(null));
                ImageUtil.write(
                        bufferedImage,
                        new File(previewHomeDir + mediaDir + "/" + media.getFileName()));
            } else {
                OutputStream output =
                        new FileOutputStream(
                                new File(previewHomeDir + mediaDir + "/" + media.getFileName()));
                IoUtil.write(output, true, multipartFile.getBytes());
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error(e.getMessage(), e);
            }
        }
        media.setUrl(mediaDir + "/" + media.getFileName());
        save(media);
        return media;
    }

    @Override
    public void deleteMedia(Long id) {
        deleteMedias(Collections.singletonList(id));
    }

    @Override
    public List<AntMedia> findByUrls(List<String> imageUrls) {
        // 每5个URL做一次批量查询
        List<List<String>> temps = CollectionUtil.split(imageUrls, 5);
        List<AntMedia> medias = new ArrayList<>();
        temps.forEach(
                urls -> {
                    QueryWrapper<AntMedia> queryWrapper = new QueryWrapper<>();
                    queryWrapper.in("url", urls);
                    medias.addAll(list(queryWrapper));
                });
        return medias;
    }

    @Override
    public List<AntMedia> findMediasByArticle(AntArticle article) {
        List<AntArticleMedia> articleMedias =
                articleMediaService.findArticleMediaRelations(article);
        List<Long> mediaIds =
                articleMedias.stream()
                        .map(AntArticleMedia::getMediaId)
                        .collect(Collectors.toList());
        return listByIds(mediaIds);
    }
}
